using System;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.WowAddonStudio.FrameXml.Serialization.TypeConverters
{
	/// <summary>
	/// Provides a type converter to convert expandable objects to and from various other representations.
	/// </summary>
	public class ResizeBoundsTypeConverter : ExpandableObjectConverter
	{
		private const string separator = "|";
		private readonly DimensionTypeConverter dimensionTypeConverter = new DimensionTypeConverter();

		/// <summary>
		/// Returns whether this converter can convert the object to the specified type, using the specified context.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
		/// <param name="destinationType">A <see cref="T:System.Type"/> that represents the type you want to convert to.</param>
		/// <returns>
		/// true if this converter can perform the conversion; otherwise, false.
		/// </returns>
		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			if (destinationType == typeof (ResizeBounds))
				return true;

			return dimensionTypeConverter.CanConvertTo(context, destinationType);
		}

		/// <summary>
		/// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
		/// <param name="sourceType">A <see cref="T:System.Type"/> that represents the type you want to convert from.</param>
		/// <returns>
		/// true if this converter can perform the conversion; otherwise, false.
		/// </returns>
		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			if (sourceType == typeof(string))
				return true;

			return dimensionTypeConverter.CanConvertFrom(context, sourceType);
		}

		/// <summary>
		/// Converts the given value object to the specified type, using the specified context and culture information.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
		/// <param name="culture">A <see cref="T:System.Globalization.CultureInfo"/>. If null is passed, the current culture is assumed.</param>
		/// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
		/// <param name="destinationType">The <see cref="T:System.Type"/> to convert the <paramref name="value"/> parameter to.</param>
		/// <returns>
		/// An <see cref="T:System.Object"/> that represents the converted value.
		/// </returns>
		/// <exception cref="T:System.ArgumentNullException">The <paramref name="destinationType"/> parameter is null. </exception>
		/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
		                                 Type destinationType)
		{
			if ((destinationType == typeof (String)) && (value is ResizeBounds))
			{
				var resizeBoundsObject = (ResizeBounds) value;
				string resizeBounds =
					String.Concat((string)dimensionTypeConverter.ConvertTo(context, culture, resizeBoundsObject.MinResize, destinationType),
					              separator,
								  (string)dimensionTypeConverter.ConvertTo(context, culture, resizeBoundsObject.MaxResize, destinationType));
				return resizeBounds;
			}
			return dimensionTypeConverter.ConvertTo(context, culture, value, destinationType);
		}

		/// <summary>
		/// Converts the given object to the type of this converter, using the specified context and culture information.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
		/// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
		/// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
		/// <returns>
		/// An <see cref="T:System.Object"/> that represents the converted value.
		/// </returns>
		/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			if (value is string)
			{
				var textValue = (string) value;
				if (!textValue.Contains(separator))
					throw new ArgumentException("Invalid ResizeBounds. Use '|' separator for dimension declarations.");

				var dimensionTexts = textValue.Split('|');

				if (dimensionTexts.Length != 2)
					throw new ArgumentException("Invalid count of dimension.");

				return new ResizeBounds
				       	{
							MinResize = dimensionTypeConverter.ConvertFrom(context, culture, dimensionTexts[0]) as Dimension,
							MaxResize = dimensionTypeConverter.ConvertFrom(context, culture, dimensionTexts[1]) as Dimension
				       	};
			}
			return dimensionTypeConverter.ConvertFrom(context, culture, value);
		}
	}
}